package ai.fabu.dataplatform.service.impl;

import ai.fabu.dataplatform.bean.user.User;
import ai.fabu.dataplatform.constant.ResultCode;
import ai.fabu.dataplatform.help.Result;
import ai.fabu.dataplatform.service.ApiForUserService;
import ai.fabu.dataplatform.utils.StringUtil;
import ai.fabu.dataplatform.utils.TimeUtil;
import com.mongodb.client.result.DeleteResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotBlank;
import java.security.NoSuchAlgorithmException;

import static ai.fabu.dataplatform.constant.ConstantName.PASSWORD;
import static ai.fabu.dataplatform.constant.ConstantName.UPDATE_TIME;
import static ai.fabu.dataplatform.constant.ConstantName.USER_NAME;

@Service
@Slf4j
public class ApiForUserServiceImpl implements ApiForUserService {
    @Autowired
    MongoOperations mongoOperations;

    @Override
    public Result addUser(@NotBlank String userName, @NotBlank String password) {
        String methodName = new Exception().getStackTrace()[0].getMethodName();
        log.info("{}: user name: {}", methodName, userName);
        Result result = new Result();
        password = userName.charAt(0) + password + userName.charAt(userName.length()-1);
        String md5Password = null;
        try {
            md5Password = StringUtil.getMD5(password);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        Query query = new Query();
        query.addCriteria(Criteria.where(USER_NAME).is(userName));
        if(mongoOperations.exists(query, User.class)){
            log.info("{}: user name exists", methodName);
            result.returnWithoutValue(ResultCode.USER_NAME_DUPLICATE_ERROR);
            return result;
        }
        User user = User.staticUser(userName, md5Password);
        mongoOperations.insert(user);
        result.returnWithoutValue(ResultCode.SUCCESS);
        return result;
    }

    @Override
    public Result removeUser(@NotBlank String userName) {
        String methodName = new Exception().getStackTrace()[0].getMethodName();
        log.info("{}: user name: {}", methodName, userName);
        Result result = new Result();
        Query query = new Query();
        query.addCriteria(Criteria.where(USER_NAME).is(userName));
        mongoOperations.remove(query, User.class);
        result.returnWithoutValue(ResultCode.SUCCESS);
        return result;
    }

    @Override
    public Result<Boolean> verifyUser(@NotBlank String userName, @NotBlank String password) {
        String methodName = new Exception().getStackTrace()[0].getMethodName();
        log.info("{}: user name: {}", methodName, userName);
        Result<Boolean> result = new Result<>();
        Query query = new Query();
        query.addCriteria(Criteria.where(USER_NAME).is(userName));
        query.fields().include(PASSWORD);
        User user = mongoOperations.findOne(query, User.class);
        if(user == null){
            log.info("{}: user name not exists");
            result.returnWithoutValue(ResultCode.USER_NAME_NOT_EXISTS_ERROR);
            return result;
        }
        String realPassword = user.getPassword();
        try{
            password = StringUtil.getMD5(userName.charAt(0) + password + userName.charAt(userName.length()-1));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        if(password.equals(realPassword))  result.returnWithValue(ResultCode.SUCCESS, true);
        else result.returnWithValue(ResultCode.USER_NOT_VERIFY_ERROR, false);
        return result;
    }

    @Override
    public Result updateUserPassword(@NotBlank String userName, @NotBlank String oldPassword, @NotBlank String newPassword) {
        String methodName = new Exception().getStackTrace()[0].getMethodName();
        log.info("{}: user name: {}", methodName, userName);
        Result result = new Result();
        Result<Boolean> verifyResult = verifyUser(userName, oldPassword);
        if(verifyResult.getCode() != ResultCode.SUCCESS.getCode()){
            log.error("{}: verify user error");
            result.returnWithOutValue(verifyResult);
            return result;
        }
        String password = userName.charAt(0) + newPassword + userName.charAt(userName.length()-1);
        try {
            password = StringUtil.getMD5(password);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        Query query = new Query();
        query.addCriteria(Criteria.where(USER_NAME).is(userName));
        Update update = new Update();
        update.set(PASSWORD, password);
        update.set(UPDATE_TIME, TimeUtil.getNowTimestampLong());
        mongoOperations.updateFirst(query, update, User.class);
        result.returnWithoutValue(ResultCode.SUCCESS);
        return result;
    }
}
